<?php
/**
 * Zend Framework
 * LICENSE
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 * @category Zend
 * @package Zend_Validate
 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license http://framework.zend.com/license/new-bsd New BSD License
 * @version $Id: Abstract.php 25105 2012-11-07 20:33:22Z rob $
 */
/**
 *
 * @see Zend_Validate_Interface
 */
require_once 'Zend/Validate/Interface.php';

/**
 *
 * @category Zend
 * @package Zend_Validate
 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license http://framework.zend.com/license/new-bsd New BSD License
 */
abstract class Zend_Validate_Abstract implements Zend_Validate_Interface {

    /**
     * The value to be validated
     * @var mixed
     */
    protected $_value;

    /**
     * Additional variables available for validation failure messages
     * @var array
     */
    protected $_messageVariables = array();

    /**
     * Validation failure message template definitions
     * @var array
     */
    protected $_messageTemplates = array();

    /**
     * Array of validation failure messages
     * @var array
     */
    protected $_messages = array();

    /**
     * Flag indidcating whether or not value should be obfuscated in error
     * messages
     * @var bool
     */
    protected $_obscureValue = false;

    /**
     * Array of validation failure message codes
     * @var array
     * @deprecated Since 1.5.0
     */
    protected $_errors = array();

    /**
     * Translation object
     * @var Zend_Translate
     */
    protected $_translator;

    /**
     * Default translation object for all validate objects
     * @var Zend_Translate
     */
    protected static $_defaultTranslator;

    /**
     * Is translation disabled?
     * @var Boolean
     */
    protected $_translatorDisabled = false;

    /**
     * Limits the maximum returned length of a error message
     * @var Integer
     */
    protected static $_messageLength =  - 1;

    /**
     * Returns array of validation failure messages
     * @return array
     */
    public function getMessages () {
        return $this -> _messages;
    }

    /**
     * Returns an array of the names of variables that are used in constructing validation failure messages
     * @return array
     */
    public function getMessageVariables () {
        return array_keys ($this -> _messageVariables);
    }

    /**
     * Returns the message templates from the validator
     * @return array
     */
    public function getMessageTemplates () {
        return $this -> _messageTemplates;
    }

    /**
     * Sets the validation failure message template for a particular key
     * @param string $messageString
     * @param string $messageKey OPTIONAL
     * @return Zend_Validate_Abstract Provides a fluent interface
     * @throws Zend_Validate_Exception
     */
    public function setMessage ($messageString, $messageKey = null) {
        if ($messageKey === null) {
            $keys = array_keys ($this -> _messageTemplates);
            foreach ($keys as $key) {
                $this -> setMessage ($messageString, $key);
            }
            return $this;
        }
        if ( ! isset ($this -> _messageTemplates[$messageKey])) {
            require_once 'Zend/Validate/Exception.php';
            throw new Zend_Validate_Exception ("No message template exists for key '$messageKey'");
        }
        $this -> _messageTemplates[$messageKey] = $messageString;
        return $this;
    }

    /**
     * Sets validation failure message templates given as an array, where the array keys are the message keys,
     * and the array values are the message template strings.
     * @param array $messages
     * @return Zend_Validate_Abstract
     */
    public function setMessages (array $messages) {
        foreach ($messages as $key => $message) {
            $this -> setMessage ($message, $key);
        }
        return $this;
    }

    /**
     * Magic function returns the value of the requested property, if and only if it is the value or a
     * message variable.
     * @param string $property
     * @return mixed
     * @throws Zend_Validate_Exception
     */
    public function __get ($property) {
        if ($property == 'value') {
            return $this -> _value;
        }
        if (array_key_exists ($property, $this -> _messageVariables)) {
            return $this -> {$this -> _messageVariables[$property]};
        }
        /**
         *
         * @see Zend_Validate_Exception
         */
        require_once 'Zend/Validate/Exception.php';
        throw new Zend_Validate_Exception ("No property exists by the name '$property'");
    }

    /**
     * Constructs and returns a validation failure message with the given message key and value.
     * Returns null if and only if $messageKey does not correspond to an existing template.
     * If a translator is available and a translation exists for $messageKey,
     * the translation will be used.
     * @param string $messageKey
     * @param string $value
     * @return string
     */
    protected function _createMessage ($messageKey, $value) {
        if ( ! isset ($this -> _messageTemplates[$messageKey])) {
            return null;
        }
        $message = $this -> _messageTemplates[$messageKey];
        if (null !== ($translator = $this -> getTranslator ())) {
            if ($translator -> isTranslated ($messageKey)) {
                $message = $translator -> translate ($messageKey);
            } else {
                $message = $translator -> translate ($message);
            }
        }
        if (is_object ($value)) {
            if ( ! in_array ('__toString', get_class_methods ($value))) {
                $value = get_class ($value) . ' object';
            } else {
                $value = $value -> __toString ();
            }
        } else {
            $value = implode ((array) $value);
        }
        if ($this -> getObscureValue ()) {
            $value = str_repeat ('*', strlen ($value));
        }
        $message = str_replace ('%value%', $value, $message);
        foreach ($this -> _messageVariables as $ident => $property) {
            $message = str_replace ("%$ident%", implode (' ', (array) $this -> $property), $message);
        }
        $length = self::getMessageLength ();
        if (($length >  - 1) && (strlen ($message) > $length)) {
            $message = substr ($message, 0, (self::getMessageLength () - 3)) . '...';
        }
        return $message;
    }

    /**
     *
     * @param string $messageKey
     * @param string $value OPTIONAL
     * @return void
     */
    protected function _error ($messageKey, $value = null) {
        if ($messageKey === null) {
            $keys = array_keys ($this -> _messageTemplates);
            $messageKey = current ($keys);
        }
        if ($value === null) {
            $value = $this -> _value;
        }
        $this -> _errors[] = $messageKey;
        $this -> _messages[$messageKey] = $this -> _createMessage ($messageKey, $value);
    }

    /**
     * Sets the value to be validated and clears the messages and errors arrays
     * @param mixed $value
     * @return void
     */
    protected function _setValue ($value) {
        $this -> _value = $value;
        $this -> _messages = array();
        $this -> _errors = array();
    }

    /**
     * Returns array of validation failure message codes
     * @return array
     * @deprecated Since 1.5.0
     */
    public function getErrors () {
        return $this -> _errors;
    }

    /**
     * Set flag indicating whether or not value should be obfuscated in messages
     * @param bool $flag
     * @return Zend_Validate_Abstract
     */
    public function setObscureValue ($flag) {
        $this -> _obscureValue = (bool) $flag;
        return $this;
    }

    /**
     * Retrieve flag indicating whether or not value should be obfuscated in
     * messages
     * @return bool
     */
    public function getObscureValue () {
        return $this -> _obscureValue;
    }

    /**
     * Set translation object
     * @param Zend_Translate|Zend_Translate_Adapter|null $translator
     * @return Zend_Validate_Abstract
     */
    public function setTranslator ($translator = null) {
        if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) {
            $this -> _translator = $translator;
        } elseif ($translator instanceof Zend_Translate) {
            $this -> _translator = $translator -> getAdapter ();
        } else {
            require_once 'Zend/Validate/Exception.php';
            throw new Zend_Validate_Exception ('Invalid translator specified');
        }
        return $this;
    }

    /**
     * Return translation object
     * @return Zend_Translate_Adapter null
     */
    public function getTranslator () {
        if ($this -> translatorIsDisabled ()) {
            return null;
        }
        if (null === $this -> _translator) {
            return self::getDefaultTranslator ();
        }
        return $this -> _translator;
    }

    /**
     * Does this validator have its own specific translator?
     * @return bool
     */
    public function hasTranslator () {
        return (bool) $this -> _translator;
    }

    /**
     * Set default translation object for all validate objects
     * @param Zend_Translate|Zend_Translate_Adapter|null $translator
     * @return void
     */
    public static function setDefaultTranslator ($translator = null) {
        if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) {
            self::$_defaultTranslator = $translator;
        } elseif ($translator instanceof Zend_Translate) {
            self::$_defaultTranslator = $translator -> getAdapter ();
        } else {
            require_once 'Zend/Validate/Exception.php';
            throw new Zend_Validate_Exception ('Invalid translator specified');
        }
    }

    /**
     * Get default translation object for all validate objects
     * @return Zend_Translate_Adapter null
     */
    public static function getDefaultTranslator () {
        if (null === self::$_defaultTranslator) {
            require_once 'Zend/Registry.php';
            if (Zend_Registry::isRegistered ('Zend_Translate')) {
                $translator = Zend_Registry::get ('Zend_Translate');
                if ($translator instanceof Zend_Translate_Adapter) {
                    return $translator;
                } elseif ($translator instanceof Zend_Translate) {
                    return $translator -> getAdapter ();
                }
            }
        }
        return self::$_defaultTranslator;
    }

    /**
     * Is there a default translation object set?
     * @return boolean
     */
    public static function hasDefaultTranslator () {
        return (bool) self::$_defaultTranslator;
    }

    /**
     * Indicate whether or not translation should be disabled
     * @param bool $flag
     * @return Zend_Validate_Abstract
     */
    public function setDisableTranslator ($flag) {
        $this -> _translatorDisabled = (bool) $flag;
        return $this;
    }

    /**
     * Is translation disabled?
     * @return bool
     */
    public function translatorIsDisabled () {
        return $this -> _translatorDisabled;
    }

    /**
     * Returns the maximum allowed message length
     * @return integer
     */
    public static function getMessageLength () {
        return self::$_messageLength;
    }

    /**
     * Sets the maximum allowed message length
     * @param integer $length
     */
    public static function setMessageLength ($length = -1) {
        self::$_messageLength = $length;
    }

}
